/*
 * Fpga.c
 *
 *  Created on: Oct 13, 2018
 *      Author: ax
 */
#include <Timer.h>
#include <Device.h>
#include <Hw/Fpga.h>

typedef volatile Uint16 FpgaReg;

static struct {
    FpgaReg SOC;//soc id
    FpgaReg GPI;//mirror for dsp gpio
    FpgaReg SSEL;//nor flash high 16 bit address select

    struct {
        #define LOCAL   0
        #define REMOTE  1
        FpgaReg VAL[2];
    } TSEN[5];//temperature sensor

    FpgaReg DDRS;//ddr status for fpga
    FpgaReg SRIOS[2];//srio status for srio port[1:0]

    //0x10
    struct {
        FpgaReg DAT;//rw 8bit for r/tx fifo
        FpgaReg RCNT;//ro, rx avilable in fifo
        FpgaReg TCNT;//ro, to tx in fifo
        FpgaReg FCNT;//ro t/r fifo deepth
        FpgaReg rsvd[4];
    } RS422[2];

    //0x20
    struct {
        FpgaReg DIR;//b[3:0] for ch[3:0],0 rx; 1 tx
        FpgaReg DAT[4];//w13 loop to r24
    } GIO;
}* hEfr = (void*)0x78000000;

SocId Hw_geSoctId(void) {
    return hEfr->SOC;
}

CoreId Hw_getCoreId(void) {
    return (Hw_geSoctId() << 3) | DNUM;
}

void Nor_windowSelect(Uint32 offset) {
    short sect = offset >> 16;//shift of 128K
    hEfr->SSEL = sect;
}

unsigned                /* @return : 0 - 成功； 其他 - 失败 */
adt7461ReadLocalTemp(   /* @function : 获取温度值 */
    unsigned channel,   /* @input : 获取的温度的通道/对象，@see TemperatureSensorChannel */
    int * temperature   /* @output : 温度值存储地址 */
){
    *temperature = hEfr->TSEN[channel].VAL[LOCAL];
    return 0;
}

int                 /* @return: 0 - 成功； 1 - 超时； -1 - 失败 */
fpgaUartSend(       /* @function: 通过EMIF向FPGA的RS422发送数据 */
    Uint8  ch,   /* @input ： 发送通道 */
    Uint8 * pByte,    /* @input : 待发送的数据起始地址 */
    unsigned len,   /* @input : 发送长度 */
    int timeOut     /* @input : 超时，步进为500ns */
){
    assert(ch < 2);

    unsigned idx = 0;
    short fcnt = hEfr->RS422[ch].FCNT;
    Timestamp to = Timer_getStamp() + timeOut * TO_STEP;

    while (to > Timer_getStamp()) {
        short txable = fcnt- hEfr->RS422[ch].TCNT;
        if (txable == 0) continue;
        //else
        for (/*idx | txable*/; txable > 0; txable--) {
            if (idx++ >= len) return RS422_OK;
            hEfr->RS422[ch].DAT = *pByte++;
        }
    }

    return (idx >= len) ? RS422_OK : RS422_TO;
}

int                     /* @return: 0 - 成功； 1 - 超时； -1 - 失败 */
fpgaUartRcv(            /* @function: 通过EMIF从FPGA的RS422接收数据 */
    unsigned ch,        /* @input ： 接收通道 */
    Uint8 * pByte,     /* @output : 接收到的数据起始地址 */
    unsigned* pByteLen, /* @output : 接收到的数据的长度 */
    int timeOut         /* @input : 超时，步进为500ns */
){
    assert(ch < 2);

    unsigned idx = 0;
    unsigned len = *pByteLen;
    Timestamp to = Timer_getStamp() + timeOut * TO_STEP;

    while (to > Timer_getStamp()) {
        short rxable =hEfr->RS422[ch].RCNT;
        if (rxable == 0) continue;
        //else
        for (/*idx | txable*/; rxable > 0; rxable--) {
            *pByte++ = hEfr->RS422[ch].DAT;
            if (idx++ >= len)
                return RS422_OK;
        }
    }
    *pByteLen = idx;

    return (idx >= len) ? RS422_OK : RS422_TO;
}

Uint8                  /* @return : 0 - 成功； 0xff - 失败 ,TODO 原接口文档要求在无符号数返回-1，臣妾做不到啊。。。 */
fpgaGpioSetDir(         /* @function : 设置FPGA的GPIO管脚方向 */
    Uint32 channel,   /* @input :  @see GPIO_FpgaChannel, 内部接口不检查参数的有效性，以便用户后续更多的GPIO时前向兼容 */
    Uint32 type       /* @input : @see GPIO_FpgaDir */
){
    assert(channel < 4);

    if (type & 1) hEfr->GIO.DIR |=  (type & 1) << channel;
    else hEfr->GIO.DIR &= ~(1 << channel);

    return 0;
}

int                     /* @return : 0 - 成功； -1 - 失败 */
fpgaGpioWrite(          /* @function : 设置FPGA的GPIO管脚状态 */
    Uint32 channel,   /* @input :  @see GPIO_FpgaChannel, 内部接口不检查参数的有效性，以便用户后续更多的GPIO时前向兼容 */
    Uint8  data        /* @input : 该channel所有pin对应的状态（bitmap8） @see GPIO_Status */
){
    assert(channel < 4);

    hEfr->GIO.DAT[channel] = data;

    return 0;
}

int                     /* @return : 0 - 成功； -1 - 失败 */
fpgaGpioRead(           /* @function : 获取FPGA的GPIO管脚状态 */
    Uint32  channel,  /* @input :  @see GPIO_FpgaChannel, 内部接口不检查参数的有效性，以便用户后续更多的GPIO时前向兼容 */
    Uint8*  data       /* @output : 该channel所有pin的状态（bitmap8） @see GPIO_Status */
){
    assert(channel < 4);

    *data = hEfr->GIO.DAT[channel];

    return 0;
}
